#!/usr/bin/env python3
#
# Copyright 2021 Graviti. Licensed under MIT License.
#

"""The implementation of the TensorBay classification label."""

from typing import Any, Dict, Optional, Type, TypeVar

from tensorbay.label.basic import SubcatalogBase, _LabelBase
from tensorbay.label.supports import AttributesMixin, CategoriesMixin
from tensorbay.utility import common_loads


class ClassificationSubcatalog(SubcatalogBase, CategoriesMixin, AttributesMixin):
    """This class defines the subcatalog for classification type of labels.

    Attributes:
        description: The description of the entire classification subcatalog.
        categories: All the possible categories in the corresponding dataset
            stored in a :class:`~tensorbay.utility.name.NameList`
            with the category names as keys
            and the :class:`~tensorbay.label.supports.CategoryInfo` as values.
        category_delimiter: The delimiter in category values indicating parent-child relationship.
        attributes: All the possible attributes in the corresponding dataset
            stored in a :class:`~tensorbay.utility.name.NameList`
            with the attribute names as keys
            and the :class:`~tensorbay.label.attribute.AttributeInfo` as values.

    Examples:
        *Initialization Method 1:* Init from ``ClassificationSubcatalog.loads()`` method.

        >>> catalog = {
        ...     "CLASSIFICATION": {
        ...         "categoryDelimiter": ".",
        ...         "categories": [
        ...             {"name": "a"},
        ...             {"name": "b"},
        ...         ],
        ...          "attributes": [{"name": "gender", "enum": ["male", "female"]}],
        ...     }
        ... }
        >>> ClassificationSubcatalog.loads(catalog["CLASSIFICATION"])
        ClassificationSubcatalog(
          (category_delimiter): '.',
          (categories): NameList [...],
          (attributes): NameList [...]
        )

        *Initialization Method 2:* Init an empty ClassificationSubcatalog
        and then add the attributes.

        >>> from tensorbay.utility import NameList
        >>> from tensorbay.label import CategoryInfo, AttributeInfo, KeypointsInfo
        >>> categories = NameList()
        >>> categories.append(CategoryInfo("a"))
        >>> attributes = NameList()
        >>> attributes.append(AttributeInfo("gender", enum=["female", "male"]))
        >>> classification_subcatalog = ClassificationSubcatalog()
        >>> classification_subcatalog.category_delimiter = "."
        >>> classification_subcatalog.categories = categories
        >>> classification_subcatalog.attributes = attributes
        >>> classification_subcatalog
        ClassificationSubcatalog(
          (category_delimiter): '.',
          (categories): NameList [...],
          (attributes): NameList [...]
        )

    """


class Classification(_LabelBase):
    """This class defines the concept of classification label.

    :class:`Classification` is the classification type of label,
    which applies to different types of data, such as images and texts.

    Arguments:
        category: The category of the label.
        attributes: The attributes of the label.

    Attributes:
        category: The category of the label.
        attributes: The attributes of the label.

    Examples:
        >>> Classification(category="example", attributes={"attr": "a"})
        Classification(
          (category): 'example',
          (attributes): {...}
        )

    """

    _T = TypeVar("_T", bound="Classification")

    _repr_attrs = ("category", "attributes")

    def __init__(
        self,
        category: Optional[str] = None,
        attributes: Optional[Dict[str, Any]] = None,
    ):
        _LabelBase.__init__(self, category, attributes)

    @classmethod
    def loads(cls: Type[_T], contents: Dict[str, Any]) -> _T:
        """Loads a Classification label from a dict containing the label information.

        Arguments:
            contents: A dict containing the information of the classification label.

        Returns:
            The loaded :class:`Classification` object.

        Examples:
            >>> contents = {"category": "example", "attributes": {"key": "value"}}
            >>> Classification.loads(contents)
            Classification(
              (category): 'example',
              (attributes): {...}
            )

        """
        return common_loads(cls, contents)
